import { NamePath } from 'ant-design-vue/lib/form/interface';
import { nextTick, onUnmounted, ref, unref, watch } from 'vue';
import type { FormActionType, FormProps, FormSchema, UseFormReturnType } from '../types/form';

export function useForm(props?: FormProps): UseFormReturnType {
	const formRef = ref<Nullable<FormActionType>>(null);
	const loadedRef = ref<Nullable<boolean>>(false);

	function register(instance: FormActionType) {
		onUnmounted(() => {
			formRef.value = null;
			loadedRef.value = false;
		});
		if (unref(loadedRef) && instance === unref(formRef)) return;

		formRef.value = instance;
		loadedRef.value = true;

		watch(
			() => props,
			() => {
				props && instance.setProps(props);
			},
			{ immediate: true, deep: true },
		);
	}

	async function getForm() {
		const form = unref(formRef);
		if (!form) {
			throw new Error('请先注册form');
		}
		await nextTick();
		return form as FormActionType;
	}

	const methods: FormActionType = {
		scrollToField: async (name: NamePath, options?: ScrollOptions | undefined) => {
			const form = await getForm();
			form.scrollToField(name, options);
		},
		setProps: async (formProps: Partial<FormProps>) => {
			const form = await getForm();
			form.setProps(formProps);
		},

		updateSchema: async (data: Partial<FormSchema> | Partial<FormSchema>[]) => {
			const form = await getForm();
			form.updateSchema(data);
		},

		resetSchema: async (data: Partial<FormSchema> | Partial<FormSchema>[]) => {
			const form = await getForm();
			form.resetSchema(data);
		},

		clearValidate: async (name?: string | string[]) => {
			const form = await getForm();
			form.clearValidate(name);
		},

		resetField: async (nameList: NamePath[]) => {
			getForm().then(async form => {
				await form.resetFields(nameList);
			});
		},

		resetFields: async (nameList?: NamePath[]) => {
			getForm().then(async form => {
				await form.resetFields(nameList);
			});
		},

		removeSchemaByFiled: async (field: string | string[]) => {
			unref(formRef)?.removeSchemaByFiled(field);
		},

		getFieldValue: <T>(values: NamePath) => {
			return unref(formRef)?.getFieldValue(values) as T;
		},

		// TODO: promisify
		getFieldsValue: <T>() => {
			return unref(formRef)?.getFieldsValue() as T;
		},

		setFieldsValue: async <T extends Recordable>(values: T) => {
			const form = await getForm();
			form.setFieldsValue<T>(values);
		},

		appendSchemaByField: async (schema: FormSchema, prefixField: string | undefined, first?: boolean) => {
			const form = await getForm();
			form.appendSchemaByField(schema, prefixField, first);
		},

		submit: async (): Promise<any> => {
			const form = await getForm();
			return form.submit();
		},

		validate: async (nameList?: NamePath[]): Promise<Recordable> => {
			const form = await getForm();
			return form.validate(nameList);
		},

		validateFields: async (nameList?: NamePath[]): Promise<Recordable> => {
			const form = await getForm();
			return form.validateFields(nameList);
		},
	};

	return [register, methods];
}
